const CM_WF_PREFIX = "WfLineID";

var cmWfFrameMaker = new CultureMuncher_FrameMaker('cmFFPrefix', 'Blue');
var cmWtFrameMaker = new CultureMuncher_FrameMaker('cmTbPrefix', 'Green');
var cmWiFrameMaker = new CultureMuncher_FrameMaker('cmItPrefix', 'Red');
var cmFeIdx =0;
var cmTbIdx =0;

// official start
var CultureMuncher_Workflow = {  
	path: '',
	TableDefinition: CultureMuncher_Workflow_TableDefinition, 
	// initializes new instance of the workflow
    init: function(wfText, type) {
    	this.level = -1;
        this.type = type;
        this.workflowText = wfText.toString().replaceAll(/\s/,'');
        this.children = [];       
        this.parse(this.workflowText, this);
        this.rootPath = '';
        
    },
    // parses the input text
	parse: function(wfText, owner) {
		if (wfText.length == 0) return null;
		
		while (wfText.length > 0) {
			// obtain command name
			var cmd = wfText.substring(0, wfText.indexOf('('));
			// get rest of the text
			wfText = wfText.substring(wfText.indexOf('('));
			var args = CultureMuncher_Workflow.parseArguments(wfText);
			// cut text by arguments
			wfText = wfText.substring(args.length + 2);
			
			switch (cmd) {
				case 'Use':
					var use = new this.StepTable();					
					use.init(owner, args);
					owner.addChild(use);
					break;
				case 'ForEach':
				case 'Click':
					var fe = new this.StepForEach();
					var body = CultureMuncher_Workflow.parseArguments(wfText);
					// cut text by arguments
					wfText = wfText.substring(body.length + 2);
					var type = (cmd == 'ForEach' ? 0 : 1);
					fe.init(owner, args, body, type);					
					owner.addChild(fe);					
					// set correct level			
					if (owner instanceof CultureMuncher_Workflow.StepForEach) {
						fe.level = owner.level + 1;
					}		
					break;
				// case 'Click':
					// var cl = new this.StepClick();
					// cl.init(owner, args);
					// owner.addChild(cl);
					// break;
			}
		}
	},
	// parses input arguments
	parseArguments: function(wfText) {
		var stack = [];
		var text = '';	
		var startP = wfText[0];
		var endP = startP == '(' ? ')' : (startP == '[' ? ']' : '}')	
		var i=0;
		
		do {
			if (wfText[i] == startP) stack.push(startP);
			else if (wfText[i] == endP) stack.pop();
			text += wfText[i];
			i++;
		} while (stack.length != 0)
		
		return text.substring(1, text.length-1);
	},
	// adds new step to the workflow
    addChild: function(child) {
		this.children.push(child);		
	},
	addStep: function(step) {
		if (this.activeStep instanceof CultureMuncher_Workflow.StepForEach) {
				this.activeStep.children.push(step);
				step.parent = this.activeStep;
		} else {
			this.addChild(step);
			step.parent = this;
		} 
		this.repaint();
	},
	///////////////////////////
	// Navigation
	navigate: function() {
		var path = this.navigationRoute.pop();
		//alert('[workflow, navigate] Navigating to: ' + path);
		
		if (path == 'DONE') return;
		
		if (path.charAt(0) == '/') {
			var elem = selectNodeXPath(content.document, path);
			
			if (elem instanceof HTMLAnchorElement) {
				//alert('[workflow, navigate] navigationg to: ' + elem.href);
				window.content.document.location = elem.href;
			} else if (elem instanceof HTMLInputElement) {
				//alert('[workflow, navigate] simulating click of: ' + elem);
				elem.click();
			} else {
				//alert('[workflow, navigate] unkown element for navigation: ' + elem);
			}
			
		} else {
			window.content.document.location = path;
		}
	},
	///////////////////////////
	// Workflow methods
	createWorkflow: function() {
		// create is automatics	
	},
	loadWorkflow: function(wfId) {
		// there is only one wf per page currently
	},
	selectWorkflow: function(url) {
		if (this.navigationRoute != null && this.navigationRoute.length > 0) {
			this.navigate();
			return;
		}
		
		// save url
		this.url = url;
		this.children = [];
		this.workflowText = '';
		this.rootPath = '';
		this.activeStep = null;
		this.isValid = true;
		
		var res = CultureMuncher_Db.SelectWorkflow(url);
		var typeControl = mainWindow.document.getElementById('cmWorkflowType');
		
		if (res != null && res.length > 0) {
			// init controls
			this.id = res[0].Id;
			
			// setup the control
			typeControl.selectedIndex = res[0].Type;
			typeControl.disabled = true;
			
			return res;
		} else {
			this.id = null;
			typeControl.disabled = false;
			dump('No workflow for page: ' + url);
		}
	},
	saveWorkflow: function() {	
		// check if it's valid
		if (!CultureMuncher_Workflow.isValid &&
		    !confirm('This workflow contains errors, do you wish to save anyways?')) return;	
		if (this.id == null) {
			var type = mainWindow.document.getElementById('cmWorkflowType').selectedIndex;
			var res = CultureMuncher_Db.CreateWorkflow(this.url, this.toString(), type);
			this.id = res[0].id;
		} else {
			CultureMuncher_Db.UpdateWorkflow(this.id, this.toString());
		}
	},
	deleteWorkflow: function() {
		if (confirm('Really? Delete Workflow?')) {
			CultureMuncher_Db.DeleteWorkflow(this.id, this.toString());
		}
		
	},		
	///////////////////////////
	// Workflow step methods
	StepForEach: function() { },
	StepTable: function() { this.path = ''; this.assignments = [], this.tableName = '' },
	StepClick: function() { this.path = ''; },
	createForEachStep: function() {
		var path = get_XPath(this.activeElement);
		if (!CultureMuncher_Workflow.checkPath(path)) return;
		// only keep remaining path from parent
		path = path.replace(this.rootPath, '');
			
		var step = new this.StepForEach();
		step.path = path;
		step.children = [];
		this.addStep(step);
		step.level = step.parent.level + 1;
		return step;
	},
	createClickStep: function() {
		var step = this.createForEachStep();
		step.type = 1;
	},
	createTableStep: function() {
		var step = new this.StepTable();
		step.tableName = document.getElementById('cmTableList').selectedItem.label;
		this.addStep(step);
	},
	createSelectStep: function() {
		alert('not implemented');
	},
	selectStep: function(id, e) {			
		if (this.activeStepCtrl != null) {
			this.activeStepCtrl.css("background-color", 'transparent');
		}
		
		if (e != null && e.button == 2) {
			this.activeStep = null;
			this.activeStepCtrl = null;
			this.rootPath = null;
			if (this.activeControl != null) {
				this.activeControl.blur();
				this.activeControl.className = 'wfTbNormal';
				this.activeControl = null;			
			}
			return;
		}
		
		var ctrl = $('#' + id);
		var parts = id.replace(this.canvas.id + '_', '').split('_');
		
		// now select active step by his id
		this.activeStep = this.children[parts[0]];
		for (var i=1; i<parts.length; i++) {
			this.activeStep = this.activeStep.children[parts[i]];
		}
		//dump('workflow [selectStep]: Active step: ' + this.activeStep + '\r\n')
		this.activeStepCtrl = ctrl;
		this.activeStepCtrl.css("background-color", '#cdcdcd');
		
		// create path to root
		if (this.activeStep instanceof CultureMuncher_Workflow.StepForEach && this.activeStep.type == 1) {
			this.rootPath = '';
		} else {
			this.rootPath = this.createRootPath(this.activeStep);
		}
		
		// navigate to correct url
		var clickPar = this.getClickParent(this.activeStep);
		var differ   = clickPar != this.clickParent;
		this.clickParent = clickPar;
		
		// now navigate the document to correct parent
		if (differ) {
			// build navigation route
			this.navigationRoute = new Array();	
			this.navigationRoute.push('DONE');		
			var parent = this.clickParent;
			while (parent != null) {
				if (parent instanceof CultureMuncher_Workflow.StepForEach && parent.type == 1) {
					this.navigationRoute.push(this.createRootPath(parent));
				}
				parent = parent.parent;
			}
			this.navigationRoute.push(this.url);
			this.navigate();
		}
	},
	selectStepForActiveControl: function(ctrl) {
		if (ctrl instanceof XULElement &&
			ctrl.parentNode != null) {
			var id = ctrl.parentNode.id;
			if (id == '' || id == null) alert('[Workflow: selectStepForActiveControl] Check template! Id can\'t be null')
			this.selectStep(id, null);
		}
	},
	selectStepForActiveSubControl: function(ctrl) {
		if (ctrl instanceof XULElement &&
			ctrl.parentNode.parentNode != null) {
			var id = ctrl.parentNode.parentNode.parentNode.parentNode.parentNode.id;
			if (id == '' || id == null) alert('[Workflow: selectStepForActiveControl] Check template! Id can\'t be null')
			this.selectStep(id, null);
		}
	},
	checkPath: function(path) {
		return this.rootPath == null || this.rootPath == '' ||
				path.indexOf(this.rootPath) > -1; 
	},
	createRootPath: function(elem) {
		var path = elem.path;
		if (path.toString() == "undefined") alert('workflow [createRootPath] Root Path Error!');
		
		var parent = elem.parent;
		while (parent != null) {
			// break on click step
			if (parent.breakPath) {
				alert('Breaking the path in: ' + parent);
				break;
			}			
			path = parent.path + path;
			parent = parent.parent;
		}
		//dump('Root path: ' + path + '\r\n');
		return path;
	},
	getClickParent: function(elem) {
		var parent = elem;
		while (parent != null) {
			if (parent instanceof CultureMuncher_Workflow.StepForEach && parent.type == 1) {
				//alert('[workflow, getClickParent]: found click parent')
				return parent;
			}
			parent = parent.parent;
		}
		return null;
	},
	insertValue: function() {
		if (this.activeControl != null) {
			this.activeControl.value = this.activeElement.innerText;
			this.bindControlValue(this.activeControl);			
		}
	},
	insertPath: function() {
		if (this.activeControl != null) {
			var path = get_XPath(this.activeElement);
			if (!CultureMuncher_Workflow.checkPath(path)) return;
			path = path.replace(this.rootPath, '');
			this.activeControl.value = path;	
			this.bindControlValue(this.activeControl);	
		}
	},
	bindControlValue: function(control, type) {
		var lbl = control.label;
		var value = control.value;		
		var ass = this.activeStep.assignments[lbl];
		
		if (ass == null) {
			alert('Creating new assignment');
			ass = new CmTableAssignment(lbl);
			this.activeStep.assignments[lbl] = ass;
		}
		switch (type) {
			case 'format':
				ass.format = value;
				break;
			case 'parser':
				ass.parser = value;
				break;
			case 'regex':
				ass.regex = value;
			default:
				ass.value = value;
		}
	},
	moveStepUp: function() {
		if (this.activeStep == null) return;
		var parent = this.activeStep.parent;
		var idx = parent.children.indexOf(this.activeStep);
		if (idx == 0) return;
		
		parent.children[idx] = parent.children[idx-1];
		parent.children[idx-1] = this.activeStep;
		
		this.repaint();
	},
	moveStepDown: function() {
		if (this.activeStep == null) return;
		var parent = this.activeStep.parent;
		var idx = parent.children.indexOf(this.activeStep);
		if (idx == parent.children.length - 1) return;
		
		parent.children[idx] = parent.children[idx+1];
		parent.children[idx+1] = this.activeStep;
		
		this.repaint();
	},
	deleteCurrentStep: function() {		
		if (this.activeStep == null) {
			return;
		}
		
		if (confirm('Really?')) {			
			ArrayRemove(this.activeStep.parent.children, this.activeStep);
			this.activeStep = null;
			this.rootPath = '';
			this.repaint();
		}
	},
	//////////////////////////////////////
	// creates the workflow control
	createControl: function(doc, canvas) {
		this.doc = doc;
		this.canvas = canvas;
		this.isValid = true;
		
		// clear canvas
		$(canvas).empty();
		
		// clear frames
		cmWfFrameMaker.hideFrames();
		cmWtFrameMaker.hideFrames();
		cmWiFrameMaker.hideFrames();
		cmFeIdx = 0;
		cmTbIdx = 0;
		
		for (var i=0; i<this.children.length; i++) {
			canvas.appendChild(this.children[i].getControl(doc, canvas, i));
		}
	},
	createStepHeader: function(doc, parent, i, headerText, className) {
		//alert(headerText);
		var bodyId = parent.id + '_' + i;
        $(parent).append(headerTemplate($), {
		     id: bodyId,
		     label: headerText,
		     classname: className
		});		
		return $('#' + bodyId)[0];
	},
	repaint: function() {
		this.createControl(this.doc, this.canvas);
	},
	setActiveElement: function(elem) {
		this.activeElement = elem;
		
		mainWindow.document.getElementById('cmCurrentXPath').value =
		    get_XPath(elem);
	},
	setActiveControl: function(ctrl) {
		if (!(ctrl instanceof XULElement)) return;
		
		if (this.activeControl != null) {
			this.activeControl.className = 'wfTbNormal';
			cmWiFrameMaker.hideFrames();
		}
		this.activeControl = ctrl;
		this.activeControl.className = 'wfTbSelected';
		// select parent control for this textobox
		this.selectStepForActiveControl(ctrl);
		
		// paint frame		
		if (this.activeControl.value != '' && this.activeControl.value.charAt(0) == '/') {
			var pth = CultureMuncher_Workflow.createRootPath(this.activeStep);
			pth = pth + this.activeControl.value;
			var elem = selectNodeXPath(content.document, pth);
			if (elem != null) {
				cmWiFrameMaker.getFrame(0, elem);
			}
		}
	},	
	runWorkflow: function() {
    	window.openDialog("chrome://culturemuncher/content/workflowRunner.xul",
                  "workflowRunner", "chrome,centerscreen", 
                  {workflow: this} );
   },
	// outputs textual representation in pretty form
	toString: function() {
		var text = '';
		for (var i=0; i< this.children.length; i++) {
			text += this.children[i].toString() + '\r\n';
		}
		return text;
	},
	
}









